﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CopySniffer.Core;
using CopySniffer.Common;
using CopySniffer.Core.Tokenizers;
using System.ComponentModel;

namespace CopySniffer.Search
{
    public class CopySearcher
    {
        BackgroundWorker bgWorker;

        public CopySearcher(ISearchProvider searchProvider)
            : this(searchProvider, new RegexTokenizer())
        {
        }

        public CopySearcher(ISearchProvider searchProvider, ITokenizer tokenizer)
        {
            this.searchProvider = searchProvider;
            this.tokenizer = tokenizer;
            bgWorker = new BackgroundWorker();
            bgWorker.WorkerReportsProgress = true;
            bgWorker.WorkerSupportsCancellation = true;
            bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);
            bgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWorker_RunWorkerCompleted);
        }

        void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (RunWorkerCompletedHandler != null)
            {
                RunWorkerCompletedHandler(this, e);
            }
        }

        void bgWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            SearchArguments searchArgs = (SearchArguments)e.Argument;
            var searchInfos = SearchInfo.GetSearchInfos(searchArgs.Pieces, true).ToList();
            List<PairedSearchResults> results = new List<PairedSearchResults>();
            for (int i = 0; i < searchInfos.Count; ++i)
            {
                SearchInfo info = searchInfos[i];
                var pair = new PairedSearchResults(info, searchProvider.Search(info));
                results.Add(pair);
                bgWorker.ReportProgress(i * 100 / searchInfos.Count);
            }

            e.Result = results;
        }

        private ISearchProvider searchProvider;

        private ITokenizer tokenizer;

        public IEnumerable<PairedSearchResults> Search(string fullText, int maxSearches)
        {
            Guard.IsNotNullOrEmpty(fullText, "fullText");
            return Search(new SearchArguments(tokenizer, fullText, maxSearches));
        }

        public IEnumerable<PairedSearchResults> Search(IEnumerable<string> pieces)
        {
            Guard.IsNotNull(pieces, "pieces");
            return Search(new SearchArguments(pieces));
        }

        protected virtual IEnumerable<PairedSearchResults> Search(SearchArguments searchArgs)
        {
            var q = from info in SearchInfo.GetSearchInfos(searchArgs.Pieces, true)
                    select new PairedSearchResults(info, searchProvider.Search(info));

            return q.ToList();
        }

        public void SearchAsync(
            string fullText, 
            int maxSearches,
            RunWorkerCompletedEventHandler completedHandler)
        {
            RunWorkerCompletedHandler = completedHandler;
            bgWorker.RunWorkerAsync(new SearchArguments(tokenizer, fullText, maxSearches));
        }

        protected RunWorkerCompletedEventHandler RunWorkerCompletedHandler;

        public void CancelAsync()
        {
            bgWorker.CancelAsync();
        }



        protected struct SearchArguments
        {
            public SearchArguments(ITokenizer tokenizer, string fullText, int maxSearches)
                : this()
            {
                Pieces = tokenizer.GetTokens(fullText, maxSearches);
            }

            public SearchArguments(IEnumerable<string> pieces)
                : this()
            {
                Pieces = pieces;
            }

            public IEnumerable<string> Pieces { get; set; }
        }
    }
}
